package cn.com.anypay.manager.controller.pay;

import cn.com.anypay.manager.common.utils.AnyJsonUtils;
import cn.com.anypay.manager.dto.config.payment.WxAppConfig;
import cn.com.anypay.manager.dto.config.payment.WxpayMerchantConfig;
import cn.com.anypay.manager.dto.config.payment.WxpayServiceProviderConfig;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.Base64;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * TODO列表：
 * 1. 添加订单记录功能
 * 2. 添加订单查询接口
 * 3. 添加订单退款接口
 * 4. 添加支付结果查询接口
 * 5. 添加商户余额查询接口
 * 6. 添加交易流水记录
 * 7. 添加异常处理和日志记录
 * 8. 添加支付超时处理
 * 9. 添加并发处理机制
 */
@RestController
public class WxpayController {
    private static final Logger log = LoggerFactory.getLogger(WxpayController.class);

    @Autowired
    @Qualifier("wxPayMiniappConfig")
    private WxAppConfig miniappConfig;  // 小程序配置

    @Autowired
    @Qualifier("wxPayMpConfig")
    private WxAppConfig mpConfig;       // 公众号配置

    @Autowired
    @Qualifier("wxPayMerchantConfig")
    private WxpayMerchantConfig wxPayMerchantConfig;

    @Autowired
    @Qualifier("wxPayServiceProviderConfig")
    private WxpayServiceProviderConfig wxPayServiceProviderConfig;

    @Autowired
    private RestTemplate restTemplate;

    // 获取公众号配置
    @GetMapping("/api/config/mp")
    public Map<String, String> getMpConfig() {
        Map<String, String> config = new HashMap<>();
        config.put("type", mpConfig.getType());
        config.put("appid", mpConfig.getAppId());
        config.put("secret", mpConfig.getSecret());
        config.put("token", mpConfig.getToken());
        config.put("encodingAesKey", mpConfig.getEncodingAesKey());
        config.put("msgDataFormat", mpConfig.getMsgDataFormat());
        return config;
    }

    // RSA签名工具方法
    private String generateRSASign(String message) throws Exception {
        // 读取商户私钥
        String privateKeyPath = wxPayMerchantConfig.getPrivateKeyPath();
        String privateKey = new String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(privateKeyPath)));

        // 移除私钥文件中的头尾和换行符
        privateKey = privateKey.replace("-----BEGIN PRIVATE KEY-----", "")
                             .replace("-----END PRIVATE KEY-----", "")
                             .replaceAll("\\s+", "");

        // Base64解码私钥
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey);

        // 创建PKCS8EncodedKeySpec
        java.security.spec.PKCS8EncodedKeySpec keySpec = new java.security.spec.PKCS8EncodedKeySpec(privateKeyBytes);

        // 获取RSA密钥工厂
        java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");

        // 生成私钥
        java.security.PrivateKey rsaPrivateKey = keyFactory.generatePrivate(keySpec);

        // 创建签名实例
        java.security.Signature signature = java.security.Signature.getInstance("SHA256withRSA");
        signature.initSign(rsaPrivateKey);

        // 更新签名数据
        signature.update(message.getBytes(StandardCharsets.UTF_8));

        // 生成签名
        byte[] signBytes = signature.sign();

        // Base64编码签名
        return Base64.getEncoder().encodeToString(signBytes);
    }

    // 创建支付订单
    @PostMapping("/api/v1/payments")
    public Map<String, Object> createPayment(@RequestBody Map<String, Object> params) {
        try {
            log.info("=== 创建支付订单开始 ===");
            log.info("请求参数: {}", params);

            // 1. 参数验证
            String orderNo = (String) params.get("orderNo");
            Double amount = ((Number) params.get("amount")).doubleValue();
            String description = (String) params.get("description");
            String channel = (String) params.get("channel");
            String openId = (String) params.get("openId");

            // 2. 生成订单号 (测试用)
            orderNo = String.format("ORDER_%d_%s",
                System.currentTimeMillis(),
                UUID.randomUUID().toString().replace("-", "").substring(0, 8)
            );

            log.info("解析后的参数: orderNo={}, amount={}, description={}, channel={}, openId={}",
                orderNo, amount, description, channel, openId);

            if (orderNo == null || amount == null || openId == null) {
                log.warn("缺少必要参数9");
                return Map.of(
                    "code", -1,
                    "message", "缺少必要参数10"
                );
            }

            // 3. 验证金额
            if (amount <= 0 || amount > 50000) {
                log.warn("金额无效: {}", amount);
                return Map.of(
                    "code", -1,
                    "message", "金额无效，必须在0-50000之间"
                );
            }

            // 4. 调用微信统一下单
            log.info("开始调用微信统一下单");
            String url = wxPayMerchantConfig.getDomain() + "/v3/pay/transactions/jsapi";
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("appid", mpConfig.getAppId());
            requestBody.put("mchid", wxPayMerchantConfig.getMchId());
            requestBody.put("description", description);
            requestBody.put("out_trade_no", orderNo);
            requestBody.put("notify_url", wxPayMerchantConfig.getNotifyUrl() + "/api/pay/notify/wechat");

            Map<String, Object> amountInfo = new HashMap<>();
            amountInfo.put("total", (int)(amount * 100)); // 转换为分
            amountInfo.put("currency", "CNY");
            requestBody.put("amount", amountInfo);

            Map<String, Object> payer = new HashMap<>();
            payer.put("openid", openId);
            requestBody.put("payer", payer);

            log.info("统一下单请求参数: {}", requestBody);

            // 5. 发送请求
            log.info("开始发送统一下单请求到: {}", url);

            // 生成认证头
            String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
            String nonce = UUID.randomUUID().toString().replace("-", "");
            String message = "POST\n/v3/pay/transactions/jsapi\n" + timestamp + "\n" + nonce + "\n" + AnyJsonUtils.toJsonString(requestBody) + "\n";
            String signature = generateRSASign(message);

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.set("Accept", "application/json");
            headers.set("Authorization", "WECHATPAY2-SHA256-RSA2048 " + String.format("mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%s\",serial_no=\"%s\",signature=\"%s\"",
                wxPayMerchantConfig.getMchId(),
                nonce,
                timestamp,
                wxPayMerchantConfig.getMchSerialNo(),
                signature
            ));

            log.info("请求头: {}", headers);

            HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
            String response = responseEntity.getBody();
            log.info("统一下单响应: {}", response);

            Map<String, Object> result = AnyJsonUtils.toMap(response);

            // 6. 生成支付参数
            log.info("开始生成支付参数");
            Map<String, String> payParams = new HashMap<>();
            payParams.put("appId", mpConfig.getAppId());
            payParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
            payParams.put("nonceStr", UUID.randomUUID().toString().replace("-", ""));
            payParams.put("package", "prepay_id=" + result.get("prepay_id"));
            payParams.put("signType", "RSA");

            // 7. 生成签名
            String signStr = String.format("%s\n%s\n%s\n%s\n",
                payParams.get("appId"),
                payParams.get("timeStamp"),
                payParams.get("nonceStr"),
                payParams.get("package")
            );

            // 使用RSA签名
            String paySign = generateRSASign(signStr);
            payParams.put("paySign", paySign);

            log.info("支付参数: {}", payParams);
            log.info("=== 创建支付订单结束 ===");

            return Map.of(
                "code", 0,
                "message", "success",
                "data", Map.of(
                    "orderNo", orderNo,
                    "payParams", payParams
                )
            );
        } catch (Exception e) {
            log.error("创建支付订单失败: {}", e.getMessage(), e);
            return Map.of(
                "code", -1,
                "message", "创建支付订单失败: " + e.getMessage()
            );
        }
    }
}